package io.renren.modules.simida.service.impl;

import com.alibaba.fastjson.JSONObject;
import io.renren.common.constants.enums.ResponseStatus;
import io.renren.common.constants.enums.State;
import io.renren.common.exception.BusinessException;
import io.renren.common.rpc.OutrestSimidaFeignRpc;
import io.renren.common.utils.*;
import io.renren.modules.simida.dto.resp.UserDataRespDto;
import io.renren.modules.simida.dto.resp.UserHomePageRespDto;
import io.renren.datasource.annotation.DataSource;
import io.renren.modules.simida.entity.UserDataEntity;
import io.renren.modules.simida.service.UserDataService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import io.renren.modules.simida.dao.UserInfoDao;
import io.renren.modules.simida.entity.UserInfoEntity;
import io.renren.modules.simida.service.UserInfoService;


@Service("userInfoService")
public class UserInfoServiceImpl extends ServiceImpl<UserInfoDao, UserInfoEntity> implements UserInfoService {

    @Autowired
    private OutrestSimidaFeignRpc outrestSimidaFeignRpc;
    @Autowired
    private UserDataService userDataService;
    @Autowired
    private UserInfoDao userInfoDao;

    @Override
    @DataSource(Constant.DB_SLAVE_SIMIDA)
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<UserInfoEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("state",State.ABLE.getValue());
        queryWrapper.orderByDesc("update_time");
        queryWrapper.eq(StringUtil.isNotEmpty(params.get("gender")), "gender", params.get("gender"));
        queryWrapper.eq(StringUtil.isNotEmpty(params.get("userId")), "user_id", params.get("userId"));
        queryWrapper.likeRight(StringUtil.isNotEmpty(params.get("nickname")), "nickname", params.get("nickname"));
        boolean needTime = StringUtil.isNotEmpty(params.get("beginTime")) && StringUtil.isNotEmpty(params.get("endTime"));
        queryWrapper.between(needTime, "create_time", params.get("beginTime"), params.get("endTime"));
        IPage<UserInfoEntity> page = this.page(
                new Query<UserInfoEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    @DataSource(Constant.DB_SLAVE_SIMIDA)
    public UserHomePageRespDto queryUserInfo(Long userId) {
        UserDataEntity userDataEntity = userDataService.getById(userId);
        if (userDataEntity == null || userDataEntity.getState() == State.DISABLE.getValue()) {
            throw new BusinessException(ResponseStatus.USER_IS_NOT_EXIST);
        }
        UserHomePageRespDto userHomePageRespDto = outrestSimidaFeignRpc.queryUserInfo(userId);
        UserDataRespDto userDataRespDto = new UserDataRespDto();
        BeanUtils.copyProperties(userDataEntity, userDataRespDto);
        userHomePageRespDto.setUserData(userDataRespDto);
        return userHomePageRespDto;
    }

    @Override
    @DataSource(Constant.DB_SLAVE_SIMIDA)
    public List<JSONObject> genderGroupCount() {
        return userInfoDao.queryCountGender();
    }

    @Override
    @DataSource(Constant.DB_SLAVE_SIMIDA)
    public Map<String, List> regNumStatistics(Map<String, Object> params) {
        String startTime = (String) params.get("startTime");
        String endTime = (String) params.get("endTime");
        int calendarType = getCalendarType(startTime, endTime);
        //按照每天进行分组
        List<String> timeIntervalList = DateUtils.getIntervalTimeList(startTime, endTime, 1, calendarType);
        List<JSONObject> countRegList = userInfoDao.queryCountRegInfoGroupDay(startTime, endTime, getSqlPattern(calendarType));
        Map<String, JSONObject> groupDays = countRegList.stream()
                .collect(Collectors.toMap(jsonObject -> jsonObject.getString("days"), a -> a, (k1, k2) -> k1));
        Map<String, List> result = new HashMap<>(2);

        List<Integer> vals = new ArrayList<>(timeIntervalList.size());
        for (String interval : timeIntervalList) {
            JSONObject jsonObject = groupDays.get(interval);
            if (jsonObject == null) {
                vals.add(0);
            } else {
                vals.add(jsonObject.getInteger("userCount"));
            }
        }
        result.put("keys", timeIntervalList);
        result.put("vals", vals);
        return result;
    }

    private static int getCalendarType(String startTime, String endTime) {
        Date startDate = DateUtils.stringToDate(startTime, "yyyy-MM-dd");
        Date endDate = DateUtils.stringToDate(endTime, "yyyy-MM-dd");
        long timeDiffMs = endDate.getTime() - startDate.getTime();
        long oneYearDiffMs = 3600 * 1000 * 24 * 365L;
        if (timeDiffMs < oneYearDiffMs) {
            //没超过1年用天分组
            return Calendar.DAY_OF_MONTH;
        }
        long tenYearDiffMs = oneYearDiffMs * 10;
        if (oneYearDiffMs < timeDiffMs && timeDiffMs < tenYearDiffMs) {
            //1到10年之间用月分组
            return Calendar.MONTH;
        }
        if (timeDiffMs >= tenYearDiffMs) {
            //超过10年用年分组
            return Calendar.YEAR;
        }
        return Calendar.DAY_OF_MONTH;
    }

    private static String getSqlPattern(int calendarType) {
        if (Calendar.DAY_OF_MONTH == calendarType) {
            return "%Y-%m-%d";
        }
        if (Calendar.MONTH == calendarType) {
            return "%Y-%m";
        }
        if (Calendar.YEAR == calendarType) {
            return "%Y";
        }
        return "%Y-%m-%d";
    }
}